<?php
/*

  Copyright (c) 2008   by  maxim.oransky <maxim.oransky@gmail.com>,
  auhtor of  the-wheel-library  team

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

class Date {

	const DAY =  86400;
	const HOUR = 3600;
	const MINUTE = 60;

    private static $arrRussianMonths = array(
        'январь',
        'февраль',
        'март',
        'апрель',
        'май',
        'июнь',
        'июль',
        'август',
        'сентябрь',
        'октябрь',
        'ноябрь',
        'декабрь',
    );

    private $timestamp = 0;
    private function __construct($timestamp) {
        $this->timestamp = $timestamp;
    }

    public function getTimestamp() {
        return $this->timestamp;
    }

    /**
     * @return Date
     */
    public static function createCurrent() {
        return new Date(time());
    }

    /**
     * @return Date
     */
    public static function create($year, $month, $day = 1, $hour = 0, $min = 0, $sec = 0) {
        return new Date(mktime($hour, $min, $sec, $month, $day, $year));
    }

    /**
     * @return Date
     */
    public static function createFromSqlFormat($str) {

        if (!$str) {
            return NullDate::getInstance();
        }

        //if (!preg_match("~(\d\d\d\d)-(\d\d)-(\d\d)( (\d\d):(\d\d):(\d\d).*))?~",$str,$m))
        if (!preg_match("~(\d\d\d\d)-(\d\d)-(\d\d)( (\d\d):(\d\d):(\d\d).*)?~",$str,$m))
            throw new Exception("Incorrect sql-date '$str'");

        return empty($m[4]) ?
            self::create($m[1], $m[2] , $m[3]) :
            self::create($m[1], $m[2] , $m[3], $m[5], $m[6], $m[7]);
    }

    public function textFormat() {
        return HumanFormat::date($this->getTimestamp());
    }

    public function digitFormat() {
        return date('d.m.Y',$this->getTimestamp());
    }

    public function sqlFormat() {
        return date('Y-m-d H:i:s',$this->getTimestamp());
    }

    public function getDay() {
        return (int) date('j', $this->getTimestamp());
    }
    public function getDayWithLeadingZero() {
        return (string) date('d', $this->getTimestamp());
    }
    public function getMonth() {
        return (int) date('n', $this->getTimestamp());
    }
    public function getRussianMonthName() {
        return self::$arrRussianMonths[$this->getMonth() - 1];
    }
    public function getMonthWithLeadingZero() {
        return (string) date('m', $this->getTimestamp());
    }
    public function getYear() {
        return (int) date('Y', $this->getTimestamp());
    }

    public function getDayOfTheWeek() {
        $dayNumber = date('w', $this->getTimestamp());
        return ($dayNumber == 0) ? 7 : $dayNumber;
//      return date('w', $this->getTimestamp()) + 1;
    }

    public function getDaysInMonth() {
        return cal_days_in_month(CAL_GREGORIAN, $this->getMonth(), $this->getYear());
    }
    public function isLastDayOfTheMonth() {
        return $this->getDay() == $this->getDaysInMonth();
    }

    /**
     * @return Date
     */
    public function increaseMinutes($num) {
        $num = (int) $num;
        return new Date($this->getTimestamp() + $num * self::MINUTE);
    }

    /**
     * @return Date
     */
    public function increaseHours($num) {
        $num = (int) $num;
        return new Date($this->getTimestamp() + $num * self::HOUR);
    }

    /**
     * @return Date
     */
    public function increaseDays($num) {
        $num = (int) $num;
        return new Date($this->getTimestamp() + $num * self::DAY);
    }

    public function isNull() { return false; }
}

class NullDate extends Date {

    /**
     * @return NullDate
     */
    public static function getInstance() {
        static $instance = null;
        if ($instance === null) {
            $instance = new self(0);
        }
        return $instance;
    }

    public function getTimestamp() { throw new Exception('not implemented'); }
    public function textFormat() { return 'no date'; }
    public function digitFormat() { return 'no date'; }
    public function sqlFormat() { return '';}
    public function getDay() { throw new Exception('not implemented'); }
    public function getDayWithLeadingZero() { throw new Exception('not implemented'); }
    public function getMonth() { throw new Exception('not implemented'); }
    public function getRussianMonthName() { throw new Exception('not implemented'); }
    public function getMonthWithLeadingZero() { throw new Exception('not implemented'); }
    public function getYear() { throw new Exception('not implemented'); }
    public function getDayOfTheWeek() { throw new Exception('not implemented'); }
    public function getDaysInMonth() { throw new Exception('not implemented'); }
    public function isLastDayOfTheMonth() { throw new Exception('not implemented'); }
    public function increaseMinutes($num) { throw new Exception('not implemented'); }
    public function increaseHours($num) { throw new Exception('not implemented'); }
    public function increaseDays($num) { throw new Exception('not implemented'); }

    public function isNull() { return true; }
}
